import java.net.InetAddress;

import org.apache.axis.message.addressing.Address;
import org.apache.axis.message.addressing.EndpointReferenceType;
import org.globus.examples.services.core.rp.impl.MathQNames;
import org.globus.examples.stubs.MathService_instance_rp.MathPortType;
import org.globus.examples.stubs.MathService_instance_rp.service.MathServiceAddressingLocator;

import net.jxta.document.AdvertisementFactory;
import net.jxta.endpoint.Message;
import net.jxta.endpoint.MessageElement;
import net.jxta.endpoint.StringMessageElement;
import net.jxta.endpoint.Message.ElementIterator;
import net.jxta.id.IDFactory;
import net.jxta.pipe.PipeID;
import net.jxta.pipe.PipeMsgEvent;
import net.jxta.pipe.PipeService;
import net.jxta.platform.NetworkManager.ConfigMode;
import net.jxta.protocol.PipeAdvertisement;
import net.jxta.util.JxtaBiDiPipe;
import net.jxta.util.JxtaServerPipe;
import sun.misc.MessageUtils;
import utils.ApplicationState;
import utils.JXTAMessageUtils;
import utils.ReflectionHelper;
import utils.SerializeHelper;
import utils.ServiceType;
import utils.WorkStatus;
import utils.XMLHelper;
import advs.ServicePublisherAdvertisement;

public class ServicePublisher extends JxtaApplication
{

	public ServicePublisher()
	{
		super("ServicePublisher");
	}

	@Override
	public void Start()
	{
		if (!Initialize(ConfigMode.EDGE, "ServicePublisher", false))
		{
			return;
		}

		try
		{

			XMLHelper helper = new XMLHelper();
			InetAddress inetAddress = InetAddress.getLocalHost();
			String ip = inetAddress.getHostAddress();
			String prefix = "http://" + ip + ":8080/wsrf/services/";

			ServicePublisherAdvertisement adv;

			if (helper.getServices().size() > 0)
			{
				for (int i = 0; i < helper.getServices().size(); i++)
				{
					if (helper.getServices().get(i).contains("Math"))
					{
						adv = (ServicePublisherAdvertisement) AdvertisementFactory
								.newAdvertisement(ServicePublisherAdvertisement
										.getAdvertisementType());

						adv
								.setServiceName("org.globus.examples.clients.MathService_instance_rp.Client");
						adv.setServicePath("Execute");
						adv.setServiceType(ServiceType.Java.toString());

						String param = prefix + helper.getServices().get(i);

						adv.setReqParam(SerializeHelper
								.GetStringFromObject(param));
						adv.setParamTypes("java.lang.String"
								+ ReflectionHelper.SEPARATOR
								+ "java.lang.String");

						AddNewPublishingThread(adv);
					}

				}

			}
			if (helper.getSolvers().size() > 0)
			{
				for (int i = 0; i < helper.getSolvers().size(); i++)
				{
					adv = (ServicePublisherAdvertisement) AdvertisementFactory
							.newAdvertisement(ServicePublisherAdvertisement
									.getAdvertisementType());

					adv.setServicePath(helper.getSolvers().get(i).getPath());
					adv.setServiceName(helper.getSolvers().get(i).getName());

					adv.setReqParam(helper.getSolvers().get(i).getReqParam());

					adv.setParamTypes(helper.getSolvers().get(i)
							.getParamTypes());
					adv.setServiceType(helper.getSolvers().get(i)
							.getServiceType().toString());
					AddNewPublishingThread(adv);
				}
			}

			StartThreads();

		}
		catch (Exception e)
		{
			System.out.println("Error:" + e.getMessage());
		}
	}

	public void AddNewPublishingThread(ServicePublisherAdvertisement adv)
	{
		int expiration = 300 * 1000;
		int lifetime = 300 * 1000;
		int repeatTime = 300 * 1000;

		pipeAdv = (PipeAdvertisement) AdvertisementFactory
				.newAdvertisement(PipeAdvertisement.getAdvertisementType());

		pipeAdv.setPipeID(IDFactory.newPipeID(getGroup().getPeerGroupID()));

		pipeAdv.setDescription(adv.getServiceName() + ".pipe desc");
		pipeAdv.setName(adv.getServiceName() + ".pipe");
		pipeAdv.setType(PipeService.UnicastType);

		adv.setId(IDFactory.newCodatID(getGroup().getPeerGroupID()).toString());
		adv.setPipeAdvID(pipeAdv.getPipeID().toString());
		adv.setPeerID(getManager().getPeerID().toString());

		ThreadPublisher publisherThread = new ThreadPublisher(this);

		publisherThread.setPrintAdvOnPublish(true);

		publisherThread.addAdv(pipeAdv);
		publisherThread.addAdv(adv);

		publisherThread.setExpiration(expiration);
		publisherThread.setLifetime(lifetime);
		publisherThread.setRepeatTime(repeatTime);

		publisherThread.setName("ServicePublisher." + adv.getServiceName());
		publisherThread.setPeerToPublishTo("");

		getLoopPublishingThreads().put("Service:" + adv.getServiceName(),
				publisherThread);

	}

	@Override
	public void pipeMsgEvent(PipeMsgEvent event)
	{

		Log("Message from the client found");
		Message message = event.getMessage();

		ElementIterator elementIterator = message.getMessageElements();
		WorkStatus status = WorkStatus.HasNext;
		String methodName = "";
		String parameters = "";
		String advID = "";

		ServicePublisherAdvertisement adv = null;
		ThreadPublisher threadContainingAdv = null;

		while (elementIterator.hasNext())
		{
			MessageElement element = elementIterator.next();

			if (element.getElementName().compareTo(JXTAMessageUtils.WORKSTATUS) == 0)
			{
				status = WorkStatus.valueOf(element.toString());
				if (status == WorkStatus.HasNext)
				{
					setApplicationState(ApplicationState.Working);
				}
				else
				{
					setApplicationState(ApplicationState.Available);
				}
			}

			if (element.getElementName().compareTo(JXTAMessageUtils.ADV_ID) == 0)
			{
				Log(event.getPipeID().toString());
				advID = element.toString();
				for (ThreadPublisher thread : loopPublishingThreads.values())
				{
					for (int i = 0; i < thread.getAdvs().size(); i++)
					{
						if (thread.getAdvs().get(i).getAdvType() == ServicePublisherAdvertisement
								.getAdvertisementType())
						{
							if (((ServicePublisherAdvertisement) thread
									.getAdvs().get(i)).getId().toString()
									.compareTo(advID) == 0)
							{
								adv = (ServicePublisherAdvertisement) thread
										.getAdvs().get(i);
								threadContainingAdv = thread;
							}
						}
					}
				}

			}

			if (element.getElementName().compareTo(JXTAMessageUtils.PATH) == 0)
			{
				methodName = element.toString();
			}

			if (element.getElementName().compareTo(JXTAMessageUtils.PARAMETERS) == 0)
			{
				parameters = element.toString();
			}

			if (element.getElementName().compareTo(JXTAMessageUtils.OBJECT) == 0)
			{

				try
				{
					Object obj = SerializeHelper.GetObjectFromString(element
							.toString());

					ReflectionHelper
							.ExecuteMethodOnObject(obj, parameters, adv);
					Log(obj.toString());
					Message resultMessage = new Message();
					resultMessage.addMessageElement(new StringMessageElement(
							JXTAMessageUtils.PIPEID, threadContainingAdv
									.getPipeAdvertisement().getPipeID()
									.toString(), null));
					resultMessage.addMessageElement(new StringMessageElement(
							JXTAMessageUtils.RESULT, SerializeHelper
									.GetStringFromObject(obj), null));

					threadContainingAdv.getBidiPipe()
							.sendMessage(resultMessage);
				}
				catch (Exception e)
				{
					System.out.println("ERROR:" + e.getMessage());
				}

			}

			if (element.getElementName().compareTo(JXTAMessageUtils.ACTION) == 0)
			{
				setApplicationState(ApplicationState.valueOf(
						ApplicationState.class, element.toString()));
			}
		}

	}
}
